home *** CD-ROM | disk | FTP | other *** search
/ Young Minds / Young Minds Interactive CD-ROM.ISO / sdi / cities.c < prev    next >
Encoding:
C/C++ Source or Header  |  1987-06-18  |  7.0 KB  |  293 lines

  1. /**********************************  cities.c  ************************/
  2. #include <pixrect/pixrect_hs.h>
  3. #include <sunwindow/notify.h>
  4. #include <stdio.h>
  5. #include "sdi.h"
  6.  
  7. /*
  8.  * Copyright 1987 by Mark Weiser.
  9.  * Permission to reproduce and use in any manner whatsoever on Suns is granted
  10.  * so long as this copyright and other identifying marks of authorship
  11.  * in the code and the game remain intact and visible.  Use of this code
  12.  * in other products is reserved to me--I'm working on Mac and IBM versions.
  13.  */
  14.  
  15. /*
  16.  * Code to do things to cities.  Much of the code here consists of
  17.  * passing a routine into doto_cities, which then calls that routine
  18.  * on each city.  See the comment for doto_cities (near the end of the file)
  19.  * for more information.
  20.  */
  21.  
  22. static short default_city_data[] = {
  23. #include "default_city.h"
  24. };
  25. mpr_static(default_city_pr, 64, 64, 1, default_city_data);
  26.  
  27. static struct pixrect *city_pr_ptr = &default_city_pr;
  28. static colormap_t city_colormap, *city_colormap_ptr = NULL;
  29.  
  30. static short melted_city_data[] = {
  31. #include "melt.h"
  32. };
  33. mpr_static(melted_city_pr, 64, 64, 1, melted_city_data);
  34.  
  35.  
  36. #define MIN_SPACE 4
  37. #define MAX_CITIES 40
  38.  
  39. static int city_space, excess, global_count;
  40. static long bits_in_city;
  41.  
  42. static int do_update(), do_count(), do_placement(), do_kill(), 
  43.        do_update_all(), do_grow(), do_update_cities(), do_melt_all(); 
  44.  
  45. static int cities_inited = 0;
  46. static short cities[MAX_CITIES];
  47.  
  48.  
  49. static int growcount;    /* ugh, another weird global.
  50.                          * set by do_update_cities, used only by 'do_grow'.
  51.                          */
  52.  
  53. /*
  54.  * Read a new city pixrect from a file.
  55.  */
  56. init_city_bits(filename)
  57. char *filename;
  58. {
  59.     /* this routine is only called if there is non-default city. */
  60.     if (filename != NULL) {
  61.             char error_msg[256];
  62.             struct pixrect *tmp,*icon_load_mpr();
  63.             if ((tmp = icon_load_mpr(filename, error_msg)) == NULL) {
  64.                 printf("Could not get pr '%s'.\n", filename);
  65.                 printf("%s",error_msg);
  66.                 printf("Using default cities.\n");
  67.             } else {
  68.                 city_pr_ptr = tmp;
  69.             }
  70.     }
  71. }
  72.  
  73. /*
  74.  * Compute the positions of all the cities based on current screen size,
  75.  * and declare all the cities to be unmelted.
  76.  */
  77. init_cities()
  78. {
  79.     int i, old_num_cities = num_cities;
  80.     bits_in_city = count_bits(city_pr_ptr);
  81.     num_cities = ((max_x - MARGIN)/64) + 1;    /* bigger than possible */
  82.     city_space = 0;
  83.  
  84.     while (city_space < MIN_SPACE) {
  85.         num_cities -= 1;
  86.         city_space = ((max_x - MARGIN) - (num_cities * 64))/(num_cities-1);
  87.     };
  88.     
  89.     excess = max_x - (MARGIN + 64*num_cities + city_space*(num_cities-1));
  90.     for (i=old_num_cities; i<num_cities; i++) {
  91.         cities[i] = 1;
  92.     }    
  93.     cities_inited = 1;
  94. }
  95.  
  96. /*
  97.  * display the cities, melted or otherwise.
  98.  */
  99. place_cities(pw)
  100. Pixwin *pw;
  101. {
  102.     pw_writebackground(pw, 0, max_y-8, max_x, max_y, PIX_NOT(PIX_SRC));
  103.     doto_cities(pw, do_placement, city_pr_ptr, 0);
  104.     doto_cities(pw, do_placement, &melted_city_pr, 1);
  105. }
  106.  
  107. /* helper for 'place_cities', passed into 'doto_cities' */
  108. static int
  109. do_placement(pr, city_pr)
  110. struct pixrect *pr, *city_pr;
  111. {
  112.     pr_rop(pr, 0, 0, 64, 64, PIX_SRC, city_pr, 0, 0);
  113.     return 1;    /* this forces the new city back into the pixwin */
  114. }
  115.  
  116. /*
  117.  * Pop a new city onto the display at a random empty position.
  118.  */
  119. new_city(pw)
  120. Pixwin *pw;
  121. {
  122.     int pick, num_gone = 0, i;
  123.     for (i=0; i < num_cities; i += 1) {
  124.         if (!cities[i])
  125.             num_gone += 1;
  126.     }
  127.     if (num_gone == 0)
  128.         return;
  129.     pick = (random() % num_gone) + 1;
  130.     for (i=0; i < num_cities; i += 1) {
  131.         if (!cities[i] && !--pick)
  132.             break;
  133.     }
  134.     /* restore a random melted city */
  135.     cities[i] = 1;
  136.     do_update_cities(pw, 1, do_grow);
  137. }
  138.  
  139. /* helper for do_update_cites, grow a city. */
  140. static int
  141. do_grow(pr, speed)
  142. struct pixrect *pr;
  143. {
  144.     grow(pr, city_pr_ptr, growcount+16);
  145.     return 1;
  146. }
  147.  
  148. /* return how many died */
  149. static int global_citycount;
  150. compute_cities(pw)
  151. Pixwin *pw;
  152. {
  153.     global_citycount = 0;
  154.     doto_cities(pw, do_count, 0, 0);
  155.     return global_citycount;
  156. }
  157.  
  158. /* helper for 'compute_cities', passed into 'doto_cities' */
  159. static int
  160. do_count(pr, client)
  161. struct pixrect *pr;
  162. int *client;
  163. {
  164.     if (city_dead(pr)) {
  165.         global_citycount += 1;
  166.     }
  167.     return 0;    /* avoids pw_write in doto_cities */
  168. }
  169.  
  170. /*
  171.  * Melt or grow each city, as appropriate.
  172.  */
  173. update_cities(pw, speed)
  174. {
  175.     do_update_cities(pw, speed, do_update);
  176.     doto_cities(pw, do_kill, 0, 0);
  177. }
  178.  
  179. /* helper for 'update_cities', passed to 'do_update_cities', grows or melts. */
  180. static int
  181. do_update(pr, speed)
  182. struct pixrect *pr;
  183. int speed;
  184. {
  185.     if (city_dead(pr)) {
  186.         melt(pr, &melted_city_pr, speed);
  187.         return 1;    
  188.     } else {
  189.         grow(pr, city_pr_ptr, growcount+16);
  190.         return 1;   
  191.     }
  192. }
  193.  
  194. /* Helper for 'update_cities', passed into doto_cities, computes dead cities. */
  195. static int
  196. do_kill(pr, tmp)
  197. struct pixrect *pr;
  198. {
  199.     if (city_dead(pr))
  200.         cities[global_count] = 0;
  201.     return 0;
  202. }
  203.  
  204. /* Do what it says. */
  205. melt_all_cities(pw, speed)
  206. {
  207.     do_update_cities(pw, speed, do_melt_all);
  208. }
  209.  
  210.  
  211. /* helper for 'melt_all_cities', passed into 'do_update_cities' */
  212. static int
  213. do_melt_all(pr, speed)
  214. struct pixrect *pr;
  215. int speed;
  216. {
  217.     melt(pr, &melted_city_pr, speed);
  218.     return 1;    /* forces writing out the melted city in doto_cities */
  219. }
  220.  
  221. /*
  222.  * Call function 'helper' numerous times on each city, thus causing
  223.  * growing or melting (or both), depending upon 'helper'.
  224.  */
  225. static int
  226. do_update_cities(pw, speed, helper)
  227. int (*helper)();
  228. {
  229.     int i;
  230.     int count = (64 / speed) + 1;
  231.     for (growcount = 1; growcount < count; growcount += 1) {
  232.         /* we might plausibly batch here, but the melt looks better without */
  233.         doto_cities(pw, helper, speed, 0);
  234.     }
  235. }
  236.  
  237. /*
  238.    Cities are a kind of abstract datatype.  To do something to all
  239.    cities, pass a function and a piece of client data to 'doto_cities',
  240.    and the function will be called once for each city still in
  241.    existence (or if 'non-cities' is non-zero, once for each city NOT
  242.    still in existence.)  The calling sequence for the passed in
  243.    function will be:
  244.         func(pr, client_data);
  245.    where 'pr' is a 64x64 pixrect of a city.  If 'func' returns 0 then
  246.    'pr' is assumed to be unchanged, otherwise 'pr' is written back into
  247.    the pixwin so the change is visible. Global_count is set before the
  248.    call to the ordinal number of the city currently being operated on.
  249.  
  250.    Init_cities must be called before any city operations.
  251.  */
  252.  
  253. static char tmp_image_place[512];
  254. mpr_static(tmpcity_pr, 64, 64, 1, tmp_image_place);
  255.  
  256. doto_cities(pw, func, client_data, non_cities)
  257. Pixwin *pw;
  258. int (*func)();
  259. int *client_data;
  260. {
  261.     int x = MARGIN/2 + excess/2, stop_x = max_x - MARGIN/2 - 64;
  262.     int y = max_y - 64;
  263.     if (! cities_inited) {
  264.         /* no return from here */
  265.         printf("'doto_cities called before 'init_cities'.\n");
  266.         abort();
  267.     }
  268.     global_count = 0;
  269.     while (x <= stop_x) {
  270.         if ((!non_cities && cities[global_count]) ||
  271.                 (non_cities && !cities[global_count])) {
  272.             pw_read(&tmpcity_pr, 0, 0, 64, 64, PIX_SRC, pw, x, y);
  273.             if (func(&tmpcity_pr, client_data))
  274.                 pw_write(pw, x, y, 64, 64, PIX_SRC, &tmpcity_pr, 0, 0);
  275.         }
  276.         global_count += 1;
  277.         x += 64 + city_space;
  278.     }
  279. }
  280.  
  281. /*
  282.  * See if a city is dead.  It is if 2/3's of its pixels are clobbered.
  283.  */
  284. city_dead(pr)
  285. struct pixrect *pr;
  286. {
  287.     long bitcount = count_bits(pr);
  288.     if (bitcount < 2*bits_in_city/3)
  289.         return 1;
  290.     else return 0;
  291. }
  292.  
  293.